package com.hzchendou.blog.demo.gateway.security.filter;

import com.hzchendou.blog.demo.common.model.vo.ResultVO;
import com.hzchendou.blog.demo.common.utils.JacksonUtils;
import com.hzchendou.blog.demo.gateway.config.WhiteUrlProperties;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * @Date: 2022-05-13 15:54
 * @since: 1.0
 */
@Slf4j
public class SecurityGlobalFilter implements WebFilter {

    private WhiteUrlProperties whiteUrlProperties;

    public SecurityGlobalFilter(WhiteUrlProperties whiteUrlProperties) {
        this.whiteUrlProperties = whiteUrlProperties;
    }

    @SneakyThrows
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String path = request.getPath().pathWithinApplication().value();

        log.info("访问地址: {}", path);

        if (whiteUrlProperties.containPath(path)) {
            log.info("忽略权限校验");
            ServerHttpRequest whiteRequest = exchange.getRequest().mutate()
                    .header("Authorization", "").build();
            ServerWebExchange buildServerWebExchange = exchange.mutate().request(whiteRequest)
                    .build();
            return chain.filter(buildServerWebExchange);
        }
        return ReactiveSecurityContextHolder.getContext()
                .map(securityContext -> securityContext.getAuthentication())
                .flatMap(authentication -> {
                    if (!authentication.isAuthenticated()) {
                        ResultVO<String> resultVO = ResultVO.fail("登录异常");
                        try {
                            return response.writeWith(Mono.just(
                                    response.bufferFactory().wrap(resultVO.toJson().getBytes())));
                        } catch (Exception ex) {
                            return Mono.empty();
                        }
                    }
                    try {
                        Map<String, Object> attrs = ((JwtAuthenticationToken) authentication)
                                .getTokenAttributes();
                        String token = Base64.getEncoder()
                                .encodeToString(JacksonUtils.toJSON(attrs).getBytes(
                                        StandardCharsets.UTF_8));
                        ServerHttpRequest tokenRequest = exchange.getRequest().mutate()
                                .header("token", token)
                                .build();
                        ServerWebExchange build = exchange.mutate().request(tokenRequest).build();
                        return chain.filter(build);
                    } catch (Exception ex) {
                        return Mono.empty();
                    }
                });
    }
}
